home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / ImageMagick / montage.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  57KB  |  1,641 lines

  1. /*
  2. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  3. %                                                                             %
  4. %                                                                             %
  5. %                                                                             %
  6. %             M   M   OOO   N   N  TTTTT   AAA    GGGG  EEEEE                 %
  7. %             MM MM  O   O  NN  N    T    A   A  G      E                     %
  8. %             M M M  O   O  N N N    T    AAAAA  G  GG  EEE                   %
  9. %             M   M  O   O  N  NN    T    A   A  G   G  E                     %
  10. %             M   M   OOO   N   N    T    A   A   GGGG  EEEEE                 %
  11. %                                                                             %
  12. %                                                                             %
  13. %              Montage Magick Image File Format Image via X11.                %
  14. %                                                                             %
  15. %                                                                             %
  16. %                                                                             %
  17. %                           Software Design                                   %
  18. %                             John Cristy                                     %
  19. %                              July 1992                                      %
  20. %                                                                             %
  21. %                                                                             %
  22. %  Copyright 1994 E. I. du Pont de Nemours & Company                          %
  23. %                                                                             %
  24. %  Permission to use, copy, modify, distribute, and sell this software and    %
  25. %  its documentation for any purpose is hereby granted without fee,           %
  26. %  provided that the above Copyright notice appear in all copies and that     %
  27. %  both that Copyright notice and this permission notice appear in            %
  28. %  supporting documentation, and that the name of E. I. du Pont de Nemours    %
  29. %  & Company not be used in advertising or publicity pertaining to            %
  30. %  distribution of the software without specific, written prior               %
  31. %  permission.  E. I. du Pont de Nemours & Company makes no representations   %
  32. %  about the suitability of this software for any purpose.  It is provided    %
  33. %  "as is" without express or implied warranty.                               %
  34. %                                                                             %
  35. %  E. I. du Pont de Nemours & Company disclaims all warranties with regard    %
  36. %  to this software, including all implied warranties of merchantability      %
  37. %  and fitness, in no event shall E. I. du Pont de Nemours & Company be       %
  38. %  liable for any special, indirect or consequential damages or any           %
  39. %  damages whatsoever resulting from loss of use, data or profits, whether    %
  40. %  in an action of contract, negligence or other tortuous action, arising     %
  41. %  out of or in connection with the use or performance of this software.      %
  42. %                                                                             %
  43. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  44. %
  45. %  Montage creates a composite image by combining several separate
  46. %  images.  The images are tiled on the composite image with the name of
  47. %  the image appearing just above the individual tile.
  48. %
  49. %  The composite image is constructed in the following manner.  First,
  50. %  each image specified on the command line, except for the last, is
  51. %  scaled to fit the maximum tile size.  The maximum tile size by default
  52. %  is 256x256.  It can be modified with the -geometry command line
  53. %  argument or X resource.  Note that the maximum tile size need not be a
  54. %  square.  To respect the aspect ratio of each image append ~ to the
  55. %  geometry specification.
  56. %
  57. %  Next the composite image is initialized with the color specified by the
  58. %  -background command line argument or X resource.  The width and height
  59. %  of the composite image is determined by the maximum tile size, the
  60. %  number of tiles per row, the tile border width and height, the image
  61. %  border width, and the label height.  The number of tiles per row specifies
  62. %  how many images are to appear in each row of the composite image.  The
  63. %  default is to have an equal number of images in each row and column of the
  64. %  composite.  This value can be specified with -tiles_per_row.  The tile
  65. %  border width and height, and the image border width defaults to the value
  66. %  of the X resource -borderwidth.  It can be changed with the -borderwidth or
  67. %  -geometry command line argument or X resource.  The label height is
  68. %  determined by the font you specify with the -font command line argument or
  69. %  X resource.  If you do not specify a font, a font is choosen that allows
  70. %  the name of the image to fit the maximum width of a tiled area.  The label
  71. %  colors is determined by the -background and -foreground command line
  72. %  argument or X resource.  Note, that if the background and foreground colors
  73. %  are the same, labels will not appear.
  74. %
  75. %  Finally, each image is set onto the composite image, surrounded by its
  76. %  border color, with its name centered just below it.  The individual images
  77. %  are centered within the width of the tiled area.  The final argument on the
  78. %  command line is the name assigned to the composite image.  The image is
  79. %  written in the MIFF format and may by viewed or printed with `display'.
  80. %
  81. %  The Montage program command syntax is:
  82. %
  83. %  Usage: montage [options ...] file [ [options ...] file ...] file
  84. %
  85. %  Where options include:
  86. %    -clip geometry        preferred size and location of the clipped image
  87. %    -colors value         preferred number of colors in the image
  88. %    -colorspace type      GRAY, OHTA, RGB, XYZ, YCbCr, YIQ, or YUV
  89. %    -comment string       annotate image with comment
  90. %    -compose operator     composite operator
  91. %    -compress type        RunlengthEncoded or QEncoded
  92. %    -density geometry     vertical and horizontal density of the image
  93. %    -display server       query fonts from this X server
  94. %    -dither               apply Floyd/Steinberg error diffusion to image
  95. %    -frame                surround image with an ornamental border
  96. %    -gamma value          level of gamma correction
  97. %    -geometry geometry    preferred tile and border sizes
  98. %    -gravity direction    which direction to gravitate towards
  99. %    -interlace type       NONE, LINE, or PLANE
  100. %    -label name           assign a label to an image
  101. %    -monochrome           transform image to black and white
  102. %    -page geometry        size and location of the Postscript page
  103. %    -quality value        JPEG quality setting
  104. %    -rotate degrees       apply Paeth rotation to the image
  105. %    -scene value          image scene number
  106. %    -tiles_per_row value  number of image tiles per row
  107. %    -treedepth value      depth of the color classification tree
  108. %    -verbose              print detailed information about the image
  109. %
  110. %  In addition to those listed above, you can specify these standard X
  111. %  resources as command line options:  -background, -bordercolor -borderwidth,
  112. %  -font, -foreground, -matte, or -title.
  113. %
  114. %  Change '-' to '+' in any option above to reverse its effect.  For
  115. %  example, specify +compress to store the image as uncompressed.
  116. %
  117. %  By default, the image format of `file' is determined by its magic
  118. %  number.  To specify a particular image format, precede the filename
  119. %  with an image format name and a colon (i.e. ps:image) or specify the
  120. %  image type as the filename suffix (i.e. image.ps).  Specify 'file' as
  121. %  '-' for standard input or output.
  122. %
  123. %
  124. */
  125.  
  126. /*
  127.   Include declarations.
  128. */
  129. #include "magick.h"
  130. #include "image.h"
  131. #include "X.h"
  132. #include "compress.h"
  133.  
  134. /*
  135. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  136. %                                                                             %
  137. %                                                                             %
  138. %                                                                             %
  139. %   M o n t a g e I m a g e                                                   %
  140. %                                                                             %
  141. %                                                                             %
  142. %                                                                             %
  143. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  144. %
  145. %  Function MontageImage creates a composite image by combining several
  146. %  separate images.
  147. %
  148. %  The format of the MontageImage routine is:
  149. %
  150. %      MontageImage(display,resource_info,images,number_tiles,tiles_per_row,
  151. %        frame,compose)
  152. %
  153. %  A description of each parameter follows:
  154. %
  155. %    o display: Specifies a connection to an X server;  returned from
  156. %      XOpenDisplay.
  157. %
  158. %    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
  159. %
  160. %    o image: Specifies a pointer to a Image structure; returned from
  161. %      ReadImage.
  162. %
  163. %    o number_tiles: Specifies the number of tiles to tile.
  164. %
  165. %    o tiles_per_row: Specifies the number of arguments.
  166. %
  167. %    o frame: An integer greater than zero will force an ornamental border
  168. %      around each tile.
  169. %
  170. %    o compose: Specifies an image composite operator.
  171. %
  172. %
  173. */
  174. static int SceneCompare(x,y)
  175. const void
  176.   *x,
  177.   *y;
  178. {
  179.   Image
  180.     **image_1,
  181.     **image_2;
  182.  
  183.   image_1=(Image **) x;
  184.   image_2=(Image **) y;
  185.   return((int) (*image_1)->scene-(int) (*image_2)->scene);
  186. }
  187.  
  188. static Image *MontageImage(display,resource_info,images,number_tiles,
  189.   tiles_per_row,frame,compose)
  190. Display
  191.   *display;
  192.  
  193. XResourceInfo
  194.   *resource_info;
  195.  
  196. Image
  197.   **images;
  198.  
  199. unsigned int
  200.   number_tiles,
  201.   tiles_per_row,
  202.   frame,
  203.   compose;
  204. {
  205.   ColorPacket
  206.     border_color,
  207.     highlight_color,
  208.     matte_color,
  209.     shadow_color;
  210.  
  211.   Image
  212.     *image,
  213.     *montage_image;
  214.  
  215.   int
  216.     x,
  217.     x_offset,
  218.     y,
  219.     y_offset;
  220.  
  221.   register char
  222.     *q;
  223.  
  224.   register int
  225.     i;
  226.  
  227.   register RunlengthPacket
  228.     *p;
  229.  
  230.   RectangleInfo
  231.     label_info,
  232.     tile_info;
  233.  
  234.   unsigned int
  235.     border_width,
  236.     bevel_width,
  237.     count,
  238.     max_width,
  239.     status,
  240.     tile;
  241.  
  242.   XAnnotateInfo
  243.     annotate_info;
  244.  
  245.   XColor
  246.     background_color;
  247.  
  248.   XFontStruct
  249.     *font_info;
  250.  
  251.   XPixelInfo
  252.     pixel_info;
  253.  
  254.   XStandardColormap
  255.     *map_info;
  256.  
  257.   XVisualInfo
  258.     *visual_info;
  259.  
  260.   /*
  261.     Determine tile sizes.
  262.   */
  263.   border_width=resource_info->border_width;
  264.   if (frame)
  265.     {
  266.       bevel_width=((3*border_width) >> 3)+2;
  267.       border_width+=bevel_width << 1;
  268.     }
  269.   tile_info.x=resource_info->border_width;
  270.   tile_info.y=resource_info->border_width;
  271.   if (resource_info->image_geometry != (char *) NULL)
  272.     {
  273.       XParseGeometry(resource_info->image_geometry,&tile_info.x,
  274.         &tile_info.y,&tile_info.width,&tile_info.height);
  275.       if (tile_info.x < 0)
  276.         tile_info.x=0;
  277.       if (tile_info.y < 0)
  278.         tile_info.y=0;
  279.     }
  280.   tile_info.width=images[0]->columns;
  281.   tile_info.height=images[0]->rows;
  282.   for (tile=1; tile < number_tiles; tile++)
  283.   {
  284.     if (images[tile]->columns > tile_info.width)
  285.       tile_info.width=images[tile]->columns;
  286.     if (images[tile]->rows > tile_info.height)
  287.       tile_info.height=images[tile]->rows;
  288.   }
  289.   if (tiles_per_row == 0)
  290.     {
  291.       /*
  292.         Compute tiles per row.
  293.       */
  294.       tiles_per_row=1;
  295.       while ((tiles_per_row*tiles_per_row) < number_tiles)
  296.         tiles_per_row++;
  297.     }
  298.   /*
  299.     Initialize tile colors.
  300.   */
  301.   background_color.red=0;
  302.   background_color.green=0;
  303.   background_color.blue=0;
  304.   border_color.red=0;
  305.   border_color.green=0;
  306.   border_color.blue=0;
  307.   highlight_color=border_color;
  308.   shadow_color=border_color;
  309.   XGetAnnotateInfo(&annotate_info);
  310.   /*
  311.     Determine if any of the tiles have a label.
  312.   */
  313.   for (tile=0; tile < number_tiles; tile++)
  314.     if (images[tile]->label != (char *) NULL)
  315.       break;
  316.   if (tile == number_tiles)
  317.     display=(Display *) NULL;
  318.   if (display != (Display *) NULL)
  319.     {
  320.       /*
  321.         Initialize visual info.
  322.       */
  323.       map_info=XAllocStandardColormap();
  324.       if (map_info == (XStandardColormap *) NULL)
  325.         Error("Unable to create standard colormap","Memory allocation failed");
  326.       visual_info=XBestVisualInfo(display,map_info,resource_info);
  327.       if (visual_info == (XVisualInfo *) NULL)
  328.         Error("Unable to get visual",resource_info->visual_type);
  329.       map_info->colormap=(Colormap) NULL;
  330.       pixel_info.pixels=(unsigned long *) NULL;
  331.       /*
  332.         Initialize font info.
  333.       */
  334.       font_info=XBestFont(display,resource_info);
  335.       if (font_info == (XFontStruct *) NULL)
  336.         Error("Unable to load font",resource_info->font);
  337.       annotate_info.text=(char *) malloc(MaxTextLength*sizeof(char));
  338.       if (annotate_info.text == (char *) NULL)
  339.         Error("Unable to montage images","Memory allocation failed");
  340.       annotate_info.font_info=font_info;
  341.       annotate_info.height=font_info->ascent+font_info->descent;
  342.       /*
  343.         Determine background and border colors.
  344.       */
  345.       XGetMapInfo(visual_info,XDefaultColormap(display,visual_info->screen),
  346.         map_info);
  347.       XGetPixelInfo(display,visual_info,map_info,resource_info,(Image *) NULL,
  348.         &pixel_info);
  349.       background_color=pixel_info.background_color;
  350.       border_color.red=pixel_info.border_color.red >> 8;
  351.       border_color.green=pixel_info.border_color.green >> 8;
  352.       border_color.blue=pixel_info.border_color.blue >> 8;
  353.       matte_color.red=pixel_info.matte_color.red >> 8;
  354.       matte_color.green=pixel_info.matte_color.green >> 8;
  355.       matte_color.blue=pixel_info.matte_color.blue >> 8;
  356.       highlight_color.red=pixel_info.highlight_color.red >> 8;
  357.       highlight_color.green=pixel_info.highlight_color.green >> 8;
  358.       highlight_color.blue=pixel_info.highlight_color.blue >> 8;
  359.       shadow_color.red=pixel_info.shadow_color.red >> 8;
  360.       shadow_color.green=pixel_info.shadow_color.green >> 8;
  361.       shadow_color.blue=pixel_info.shadow_color.blue >> 8;
  362.     }
  363.   /*
  364.     Allocate image structure.
  365.   */
  366.   montage_image=AllocateImage((ImageInfo *) NULL);
  367.   if (montage_image == (Image *) NULL)
  368.     Error("Memory allocation error",(char *) NULL);
  369.   /*
  370.     Initialize Image structure.
  371.   */
  372.   montage_image->columns=
  373.     (tile_info.width+(tile_info.x+border_width)*2)*tiles_per_row;
  374.   montage_image->rows=(tile_info.height+(tile_info.y+border_width)*2+
  375.     (display ? annotate_info.height+4 : 0))*
  376.     (number_tiles/tiles_per_row+((number_tiles % tiles_per_row) != 0));
  377.   if (resource_info->title != (char *) NULL)
  378.     montage_image->rows+=((annotate_info.height+4) << 1)+(tile_info.y << 1);
  379.   montage_image->montage=(char *) malloc(MaxTextLength*sizeof(char));
  380.   count=1;
  381.   for (tile=0; tile < number_tiles; tile++)
  382.     count+=strlen(images[tile]->filename)+1;
  383.   montage_image->directory=(char *) malloc(count*sizeof(char));
  384.   montage_image->packets=montage_image->columns*montage_image->rows;
  385.   montage_image->pixels=(RunlengthPacket *)
  386.     malloc((unsigned int) montage_image->packets*sizeof(RunlengthPacket));
  387.   if ((montage_image->montage == (char *) NULL) ||
  388.       (montage_image->directory == (char *) NULL) ||
  389.       (montage_image->pixels == (RunlengthPacket *) NULL))
  390.     Error("Memory allocation error",(char *) NULL);
  391.   /*
  392.     Set montage geometry.
  393.   */
  394.   x_offset=0;
  395.   y_offset=0;
  396.   if (resource_info->title != (char *) NULL)
  397.     y_offset+=((annotate_info.height+4) << 1)+(tile_info.y << 1);
  398.   *montage_image->directory='\0';
  399.   (void) sprintf(montage_image->montage,"%dx%d%+d%+d",
  400.     (int) (tile_info.width+(tile_info.x+border_width)*2),
  401.     (int) (tile_info.height+(tile_info.y+border_width)*2+
  402.     (display ? annotate_info.height+4 : 0)),x_offset,y_offset);
  403.   /*
  404.     Initialize montage image to background color.
  405.   */
  406.   p=montage_image->pixels;
  407.   for (i=0; i < montage_image->packets; i++)
  408.   {
  409.     p->red=background_color.red >> 8;
  410.     p->green=background_color.green >> 8;
  411.     p->blue=background_color.blue >> 8;
  412.     p->index=0;
  413.     p->length=0;
  414.     p++;
  415.   }
  416.   /*
  417.     Sort images by increasing tile number.
  418.   */
  419.   i=0;
  420.   for (tile=0; tile < number_tiles; tile++)
  421.     i+=images[tile]->scene;
  422.   if (i > 0)
  423.     (void) qsort((void *) images,number_tiles,sizeof(Image *),SceneCompare);
  424.   if ((display != (Display *) NULL) && (resource_info->title != (char *) NULL))
  425.     {
  426.       /*
  427.         Copy title to the composite image.
  428.       */
  429.       (void) strcpy(annotate_info.text,resource_info->title);
  430.       annotate_info.width=
  431.         XTextWidth(font_info,annotate_info.text,strlen(annotate_info.text));
  432.       max_width=montage_image->columns;
  433.       if (((annotate_info.width+tile_info.x*2) << 1) >= max_width)
  434.         {
  435.           /*
  436.             Label is too wide-- shorten.
  437.           */
  438.           q=annotate_info.text+strlen(annotate_info.text);
  439.           do
  440.           {
  441.             *--q='\0';
  442.             if ((int) strlen(annotate_info.text) > 2)
  443.               (void) strcpy(q-2,"...");
  444.             annotate_info.width=XTextWidth(font_info,annotate_info.text,
  445.               strlen(annotate_info.text));
  446.           } while ((2*(annotate_info.width+(tile_info.x << 1))) >= max_width);
  447.         }
  448.       label_info.width=(annotate_info.width << 1)-1;
  449.       label_info.height=(annotate_info.height << 1)-1;
  450.       label_info.x=tile_info.x+(int) (montage_image->columns >> 1)-
  451.         (int) annotate_info.width;
  452.       label_info.y=tile_info.y+4;
  453.       (void) sprintf(annotate_info.geometry,"%ux%u%+d%+d",
  454.         label_info.width,label_info.height,label_info.x,label_info.y);
  455.       (void) XAnnotateImage(display,&pixel_info,&annotate_info,True,
  456.         montage_image);
  457.     }
  458.   /*
  459.     Copy tile images to the composite image.
  460.   */
  461.   x_offset=tile_info.x;
  462.   y_offset=tile_info.y;
  463.   if (display != (Display *) NULL)
  464.     if (resource_info->title != (char *) NULL)
  465.       y_offset+=((annotate_info.height+4) << 1)+(tile_info.y << 1);
  466.   *montage_image->directory='\0';
  467.   for (tile=0; tile < number_tiles; tile++)
  468.   {
  469.     /*
  470.       Copy this tile to the composite image.
  471.     */
  472.     image=images[tile];
  473.     (void) strcat(montage_image->directory,image->filename);
  474.     (void) strcat(montage_image->directory,"\n");
  475.     status=RunlengthDecodeImage(image);
  476.     if (status == False)
  477.       Error("Unable to unpack image",(char *) NULL);
  478.     if ((border_width != 0) && !frame)
  479.       {
  480.         ColorPacket
  481.           black;
  482.  
  483.         Image
  484.           *bordered_image;
  485.  
  486.         RectangleInfo
  487.           border_info;
  488.  
  489.         /*
  490.           Put a border around the image.
  491.         */
  492.         border_info.width=image->columns+((border_width-1) << 1);
  493.         border_info.height=image->rows+((border_width-1) << 1);
  494.         border_info.x=border_width-1;
  495.         border_info.y=border_width-1;
  496.         bordered_image=BorderImage(image,&border_info,&border_color,
  497.           &border_color);
  498.         if (bordered_image != (Image *) NULL)
  499.           {
  500.             DestroyImage(image);
  501.             image=bordered_image;
  502.           }
  503.         border_info.width=image->columns+2;
  504.         border_info.height=image->rows+2;
  505.         border_info.x=1;
  506.         border_info.y=1;
  507.         black.red=0;
  508.         black.green=0;
  509.         black.blue=0;
  510.         bordered_image=BorderImage(image,&border_info,&black,&black);
  511.         if (bordered_image != (Image *) NULL)
  512.           {
  513.             DestroyImage(image);
  514.             image=bordered_image;
  515.           }
  516.       }
  517.     /*
  518.       Gravitate image as specified by the tile gravity.
  519.     */
  520.     switch (resource_info->gravity)
  521.     {
  522.       case NorthWestGravity:
  523.       {
  524.         x=0;
  525.         y=0;
  526.         break;
  527.       }
  528.       case NorthGravity:
  529.       {
  530.         x=((tile_info.width+(border_width << 1))-image->columns) >> 1;
  531.         y=0;
  532.         break;
  533.       }
  534.       case NorthEastGravity:
  535.       {
  536.         x=(tile_info.width+(border_width << 1))-image->columns;
  537.         y=0;
  538.         break;
  539.       }
  540.       case WestGravity:
  541.       {
  542.         x=0;
  543.         y=((tile_info.height+(border_width << 1))-image->rows) >> 1;
  544.         break;
  545.       }
  546.       case ForgetGravity:
  547.       case StaticGravity:
  548.       case CenterGravity:
  549.       default:
  550.       {
  551.         x=((tile_info.width+(border_width << 1))-image->columns) >> 1;
  552.         y=((tile_info.height+(border_width << 1))-image->rows) >> 1;
  553.         break;
  554.       }
  555.       case EastGravity:
  556.       {
  557.         x=(tile_info.width+(border_width << 1))-image->columns;
  558.         y=((tile_info.height+(border_width << 1))-image->rows) >> 1;
  559.         break;
  560.       }
  561.       case SouthWestGravity:
  562.       {
  563.         x=0;
  564.         y=(tile_info.height+(border_width << 1))-image->rows;
  565.         break;
  566.       }
  567.       case SouthGravity:
  568.       {
  569.         x=((tile_info.width+(border_width << 1))-image->columns) >> 1;
  570.         y=(tile_info.height+(border_width << 1))-image->rows;
  571.         break;
  572.       }
  573.       case SouthEastGravity:
  574.       {
  575.         x=(tile_info.width+(border_width << 1))-image->columns;
  576.         y=(tile_info.height+(border_width << 1))-image->rows;
  577.         break;
  578.       }
  579.     }
  580.     if (frame)
  581.       {
  582.         Image
  583.           *framed_image;
  584.  
  585.         RectangleInfo
  586.           frame_info;
  587.  
  588.         /*
  589.           Put an ornamental border around this tile.
  590.         */
  591.         frame_info.width=tile_info.width+(border_width << 1);
  592.         frame_info.height=tile_info.height+(border_width << 1)+
  593.           (annotate_info.height+4);
  594.         frame_info.x=(x > 0 ? x : border_width);
  595.         frame_info.y=(y > 0 ? y : border_width);
  596.         framed_image=FrameImage(image,&frame_info,bevel_width,&matte_color,
  597.           &highlight_color,&shadow_color);
  598.         if (framed_image != (Image *) NULL)
  599.           {
  600.             DestroyImage(image);
  601.             image=framed_image;
  602.           }
  603.         x=0;
  604.         y=0;
  605.       }
  606.     /*
  607.       Composite background image with tile image.
  608.     */
  609.     CompositeImage(montage_image,compose,image,x_offset+x,y_offset+y);
  610.     if ((display != (Display *) NULL) && (image->label != (char *) NULL))
  611.       {
  612.         /*
  613.           Copy tile label to the composite image.
  614.         */
  615.         (void) strcpy(annotate_info.text,image->label);
  616.         annotate_info.width=
  617.           XTextWidth(font_info,annotate_info.text,strlen(annotate_info.text));
  618.         max_width=tile_info.width+(resource_info->border_width << 1)-8;
  619.         if (annotate_info.width >= max_width)
  620.           {
  621.             /*
  622.               Label is too wide-- shorten.
  623.             */
  624.             q=annotate_info.text+strlen(annotate_info.text);
  625.             do
  626.             {
  627.               *--q='\0';
  628.               if ((int) strlen(annotate_info.text) > 2)
  629.                 (void) strcpy(q-2,"...");
  630.               annotate_info.width=XTextWidth(font_info,annotate_info.text,
  631.                 strlen(annotate_info.text));
  632.             } while (annotate_info.width >= max_width);
  633.           }
  634.         label_info.width=annotate_info.width;
  635.         label_info.height=annotate_info.height;
  636.         label_info.x=x_offset+((tile_info.width+(border_width << 1)) >> 1)-
  637.           (annotate_info.width >> 1);
  638.         label_info.y=y_offset;
  639.         if (!frame)
  640.           label_info.y+=y+tile_info.y+image->rows+2;
  641.         else
  642.           label_info.y+=tile_info.height+(border_width << 1)-bevel_width-2;
  643.         (void) sprintf(annotate_info.geometry,"%ux%u%+d%+d",
  644.           label_info.width,label_info.height,label_info.x,label_info.y);
  645.         (void) XAnnotateImage(display,&pixel_info,&annotate_info,!frame,
  646.           montage_image);
  647.       }
  648.     DestroyImage(image);
  649.     if (((tile+1) % tiles_per_row) != 0)
  650.       x_offset+=tile_info.width+(tile_info.x+border_width)*2;
  651.     else
  652.       {
  653.         x_offset=tile_info.x;
  654.         y_offset+=tile_info.height+(tile_info.y+border_width)*2+
  655.           (display ? annotate_info.height+4 : 0);
  656.       }
  657.   }
  658.   (void) free((char *) annotate_info.text);
  659.   if (display != (Display *) NULL)
  660.     {
  661.       /*
  662.         Label is too wide-- shorten.
  663.       */
  664.       XFreeFont(display,font_info);
  665.       XFree((char *) visual_info);
  666.       XFree((char *) map_info);
  667.     }
  668.   return(montage_image);
  669. }
  670.  
  671. /*
  672. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  673. %                                                                             %
  674. %                                                                             %
  675. %                                                                             %
  676. %   U s a g e                                                                 %
  677. %                                                                             %
  678. %                                                                             %
  679. %                                                                             %
  680. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  681. %
  682. %  Function Usage displays the program command syntax.
  683. %
  684. %  The format of the Usage routine is:
  685. %
  686. %      Usage()
  687. %
  688. %
  689. */
  690. static void Usage()
  691. {
  692.   char
  693.     **p;
  694.  
  695.   static char
  696.     *options[]=
  697.     {
  698.       "-clip geometry        preferred size and location of the clipped image",
  699.       "-colors value         preferred number of colors in the image",
  700.       "-colorspace type      GRAY, OHTA, RGB, XYZ, YCbCr, YIQ, or YUV",
  701.       "-comment string       annotate image with comment",
  702.       "-compose operator     composite operator",
  703.       "-compress type        RunlengthEncoded or QEncoded",
  704.       "-density geometry     vertical and horizontal density of the image",
  705.       "-display server       query font from this X server",
  706.       "-dither               apply Floyd/Steinberg error diffusion to image",
  707.       "-frame                surround image with an ornamental border",
  708.       "-gamma value          level of gamma correction",
  709.       "-geometry geometry    preferred tile and border sizes",
  710.       "-gravity direction    which direction to gravitate towards",
  711.       "-interlace type       NONE, LINE, or PLANE",
  712.       "-label name           assign a label to an image",
  713.       "-monochrome           transform image to black and white",
  714.       "-page geometry        size and location of the Postscript page",
  715.       "-quality value        JPEG quality setting",
  716.       "-rotate degrees       apply Paeth rotation to the image",
  717.       "-scene value          image scene number",
  718.       "-tiles_per_row value  number of image tiles per row",
  719.       "-treedepth value      depth of the color classification tree",
  720.       "-verbose              print detailed information about the image",
  721.       (char *) NULL
  722.     };
  723.   (void) fprintf(stderr,
  724.     "Usage: %s [-options ...] file [ [-options ...] file ...] file\n",
  725.     client_name);
  726.   (void) fprintf(stderr,"\nWhere options include: \n");
  727.   for (p=options; *p != (char *) NULL; p++)
  728.     (void) fprintf(stderr,"  %s\n",*p);
  729.   (void) fprintf(stderr,
  730.     "\nIn addition to those listed above, you can specify these standard X\n");
  731.   (void) fprintf(stderr,
  732.     "resources as command line options:  -background, -bordercolor,\n");
  733.   (void) fprintf(stderr,
  734.     "-borderwidth, -font, -foreground, -matte, or -title\n");
  735.   (void) fprintf(stderr,
  736.     "\nChange '-' to '+' in any option above to reverse its effect.  For\n");
  737.   (void) fprintf(stderr,
  738.     "example, specify +compress to store the image as uncompressed.\n");
  739.   (void) fprintf(stderr,
  740.     "\nBy default, the image format of `file' is determined by its magic\n");
  741.   (void) fprintf(stderr,
  742.     "number.  To specify a particular image format, precede the filename\n");
  743.   (void) fprintf(stderr,
  744.     "with an image format name and a colon (i.e. ps:image) or specify the\n");
  745.   (void) fprintf(stderr,
  746.     "image type as the filename suffix (i.e. image.ps).  Specify 'file' as\n");
  747.   (void) fprintf(stderr,"'-' for standard input or output.\n");
  748.   exit(1);
  749. }
  750.  
  751. /*
  752. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  753. %                                                                             %
  754. %                                                                             %
  755. %                                                                             %
  756. %    M a i n                                                                  %
  757. %                                                                             %
  758. %                                                                             %
  759. %                                                                             %
  760. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  761. %
  762. %
  763. */
  764. int main(argc,argv)
  765. int
  766.   argc;
  767.  
  768. char
  769.   **argv;
  770. {
  771.   char
  772.     *clip_geometry,
  773.     *comment,
  774.     *density,
  775.     *gamma,
  776.     *label,
  777.     *option,
  778.     *page_geometry,
  779.     *server_name,
  780.     *write_filename;
  781.  
  782.   Display
  783.     *display;
  784.  
  785.   Image
  786.     **images,
  787.     *montage_image;
  788.  
  789.   ImageInfo
  790.     image_info;
  791.  
  792.   int
  793.     degrees,
  794.     i,
  795.     x;
  796.  
  797.   time_t
  798.     start_time;
  799.  
  800.   unsigned int
  801.     compose,
  802.     compression,
  803.     display_image,
  804.     first_scene,
  805.     frame,
  806.     image_number,
  807.     interlace,
  808.     last_scene,
  809.     quality,
  810.     maximum_images,
  811.     scene,
  812.     tiles_per_row,
  813.     verbose;
  814.  
  815.   XrmDatabase
  816.     resource_database;
  817.  
  818.   XResourceInfo
  819.     resource_info;
  820.  
  821.   /*
  822.     Display usage profile if there are no command line arguments.
  823.   */
  824.   client_name=(*argv);
  825.   if (argc < 3)
  826.     Usage();
  827.   /*
  828.     Set defaults.
  829.   */
  830.   clip_geometry=(char *) NULL;
  831.   comment=(char *) NULL;
  832.   compose=ReplaceCompositeOp;
  833.   compression=UndefinedCompression;
  834.   degrees=0;
  835.   density=(char *) NULL;
  836.   display=(Display *) NULL;
  837.   display_image=True;
  838.   first_scene=0;
  839.   frame=False;
  840.   gamma=(char *) NULL;
  841.   interlace=NoneInterlace;
  842.   label=(char *) NULL;
  843.   last_scene=0;
  844.   page_geometry=(char *) NULL;
  845.   quality=85;
  846.   resource_database=(XrmDatabase) NULL;
  847.   resource_info.border_color=(char *) NULL;
  848.   resource_info.border_width=0;
  849.   resource_info.colorspace=RGBColorspace;
  850.   resource_info.dither=False;
  851.   resource_info.gravity=CenterGravity;
  852.   resource_info.image_geometry=(char *) NULL;
  853.   resource_info.monochrome=False;
  854.   resource_info.number_colors=0;
  855.   resource_info.server_name=(char *) NULL;
  856.   resource_info.title=(char *) NULL;
  857.   resource_info.tree_depth=0;
  858.   scene=0;
  859.   server_name=(char *) NULL;
  860.   start_time=0;
  861.   tiles_per_row=0;
  862.   verbose=False;
  863.   maximum_images=MaxTextLength;
  864.   images=(Image **) malloc(maximum_images*sizeof(Image *));
  865.   if (images == (Image **) NULL)
  866.     Error("Unable to montage images","Memory allocation failed");
  867.   /*
  868.     Check for server name specified on the command line.
  869.   */
  870.   for (i=1; i < argc; i++)
  871.   {
  872.     /*
  873.       Check command line for server name.
  874.     */
  875.     option=argv[i];
  876.     if (((int) strlen(option) > 1) && ((*option == '-') || (*option == '+')))
  877.       if (strncmp("display",option+1,3) == 0)
  878.         {
  879.           /*
  880.             User specified server name.
  881.           */
  882.           display_image=(*option == '-');
  883.           if (display_image)
  884.             {
  885.               i++;
  886.               if (i == argc)
  887.                 Error("Missing server name on -display",(char *) NULL);
  888.               server_name=argv[i];
  889.             }
  890.           break;
  891.         }
  892.   }
  893.   if (display_image)
  894.     {
  895.       char
  896.         *resource_value;
  897.  
  898.       XrmDatabase
  899.         server_database;
  900.  
  901.       /*
  902.         Open X server connection.
  903.       */
  904.       display=XOpenDisplay(server_name);
  905.       if (display == (Display *) NULL)
  906.         Error("Unable to connect to X server",XDisplayName(server_name));
  907.       /*
  908.         Set our forgiving error handler.
  909.       */
  910.       XSetErrorHandler(XError);
  911.       /*
  912.         Initialize resource database.
  913.       */
  914.       XrmInitialize();
  915.       XGetDefault(display,client_name,"dummy");
  916.       resource_database=XrmGetDatabase(display);
  917.       resource_value=XResourceManagerString(display);
  918.       if (resource_value == (char *) NULL)
  919.         resource_value="";
  920.       server_database=XrmGetStringDatabase(resource_value);
  921.       XrmMergeDatabases(server_database,&resource_database);
  922.       /*
  923.         Get user defaults from X resource database.
  924.       */
  925.       XGetResourceInfo(resource_database,client_name,&resource_info);
  926.       clip_geometry=XGetResourceClass(resource_database,client_name,
  927.         "clipGeometry",(char *) NULL);
  928.       comment=XGetResourceClass(resource_database,client_name,"comment",
  929.         (char *) NULL);
  930.       resource_value=XGetResourceClass(resource_database,client_name,
  931.         "compression","RunlengthEncoded");
  932.       if (Latin1Compare("qencoded",resource_value) == 0)
  933.         compression=QEncodedCompression;
  934.       else
  935.         compression=RunlengthEncodedCompression;
  936.       density=XGetResourceClass(resource_database,client_name,"density",
  937.         (char *) NULL);
  938.       gamma=
  939.         XGetResourceClass(resource_database,client_name,"gamma",(char *) NULL);
  940.       resource_value=
  941.         XGetResourceClass(resource_database,client_name,"interlace","none");
  942.       interlace=UndefinedInterlace;
  943.       if (Latin1Compare("none",resource_value) == 0)
  944.         interlace=NoneInterlace;
  945.       if (Latin1Compare("line",resource_value) == 0)
  946.         interlace=LineInterlace;
  947.       if (Latin1Compare("plane",resource_value) == 0)
  948.         interlace=PlaneInterlace;
  949.       if (interlace == UndefinedInterlace)
  950.         Warning("Unrecognized interlace type",resource_value);
  951.       label=XGetResourceClass(resource_database,client_name,"label","%f");
  952.       page_geometry=XGetResourceClass(resource_database,client_name,
  953.         "pageGeometry",(char *) NULL);
  954.       resource_value=
  955.         XGetResourceClass(resource_database,client_name,"rotate","0");
  956.       degrees=atoi(resource_value);
  957.       resource_value=
  958.         XGetResourceClass(resource_database,client_name,"quality","85");
  959.       quality=atoi(resource_value);
  960.       resource_value=
  961.         XGetResourceClass(resource_database,client_name,"tiles_per_row","0");
  962.       tiles_per_row=atoi(resource_value);
  963.       resource_value=
  964.         XGetResourceClass(resource_database,client_name,"verbose","False");
  965.       verbose=IsTrue(resource_value);
  966.     }
  967.   /*
  968.     Composite image is the last item on the command line.
  969.   */
  970.   write_filename=argv[argc-1];
  971.   if (access(write_filename,0) == 0)
  972.     {
  973.       char
  974.         answer[2];
  975.  
  976.       (void) fprintf(stderr,"Overwrite %s? ",write_filename);
  977.       (void) gets(answer);
  978.       if (!((*answer == 'y') || (*answer == 'Y')))
  979.         exit(1);
  980.     }
  981.   /*
  982.     Parse command line.
  983.   */
  984.   image_number=0;
  985.   for (i=1; i < (argc-1); i++)
  986.   {
  987.     option=argv[i];
  988.     if (((int) strlen(option) > 1) && ((*option == '-') || (*option == '+')))
  989.       switch (*(option+1))
  990.       {
  991.         case 'b':
  992.         {
  993.           if (strncmp("background",option+1,5) == 0)
  994.             {
  995.               resource_info.background_color=(char *) NULL;
  996.               if (*option == '-')
  997.                 {
  998.                   i++;
  999.                   if (i == argc)
  1000.                     Error("Missing color on -background",(char *) NULL);
  1001.                   resource_info.background_color=argv[i];
  1002.                 }
  1003.               break;
  1004.             }
  1005.           if (strncmp("bordercolor",option+1,7) == 0)
  1006.             {
  1007.               resource_info.border_color=(char *) NULL;
  1008.               if (*option == '-')
  1009.                 {
  1010.                   i++;
  1011.                   if (i == argc)
  1012.                     Error("Missing color on -bordercolor",(char *) NULL);
  1013.                   resource_info.border_color=argv[i];
  1014.                 }
  1015.               break;
  1016.             }
  1017.           if (strncmp("borderwidth",option+1,7) == 0)
  1018.             {
  1019.               resource_info.border_width=0;
  1020.               if (*option == '-')
  1021.                 {
  1022.                   i++;
  1023.                   if ((i == argc) || !sscanf(argv[i],"%d",&x))
  1024.                     Error("Missing width on -borderwidth",(char *) NULL);
  1025.                   resource_info.border_width=atoi(argv[i]);
  1026.                 }
  1027.               break;
  1028.             }
  1029.           Error("Unrecognized option",option);
  1030.           break;
  1031.         }
  1032.         case 'c':
  1033.         {
  1034.           if (strncmp("clip",option+1,2) == 0)
  1035.             {
  1036.               clip_geometry=(char *) NULL;
  1037.               if (*option == '-')
  1038.                 {
  1039.                   i++;
  1040.                   if ((i == argc) || !sscanf(argv[i],"%d",&x))
  1041.                     Error("Missing geometry on -clip",(char *) NULL);
  1042.                   clip_geometry=argv[i];
  1043.                 }
  1044.               break;
  1045.             }
  1046.           if (strncmp("colors",option+1,7) == 0)
  1047.             {
  1048.               resource_info.number_colors=0;
  1049.               if (*option == '-')
  1050.                 {
  1051.                   i++;
  1052.                   if ((i == argc) || !sscanf(argv[i],"%d",&x))
  1053.                     Error("Missing colors on -colors",(char *) NULL);
  1054.                   resource_info.number_colors=atoi(argv[i]);
  1055.                 }
  1056.               break;
  1057.             }
  1058.           if (strncmp("colorspace",option+1,7) == 0)
  1059.             {
  1060.               resource_info.colorspace=RGBColorspace;
  1061.               if (*option == '-')
  1062.                 {
  1063.                   i++;
  1064.                   if (i == argc)
  1065.                     Error("Missing type on -colorspace",(char *) NULL);
  1066.                   option=argv[i];
  1067.                   resource_info.colorspace=UndefinedColorspace;
  1068.                   if (Latin1Compare("gray",option) == 0)
  1069.                     {
  1070.                       resource_info.colorspace=GRAYColorspace;
  1071.                       resource_info.number_colors=256;
  1072.                       resource_info.tree_depth=8;
  1073.                     }
  1074.                   if (Latin1Compare("ohta",option) == 0)
  1075.                     resource_info.colorspace=OHTAColorspace;
  1076.                   if (Latin1Compare("rgb",option) == 0)
  1077.                     resource_info.colorspace=RGBColorspace;
  1078.                   if (Latin1Compare("xyz",option) == 0)
  1079.                     resource_info.colorspace=XYZColorspace;
  1080.                   if (Latin1Compare("ycbcr",option) == 0)
  1081.                     resource_info.colorspace=YCbCrColorspace;
  1082.                   if (Latin1Compare("yiq",option) == 0)
  1083.                     resource_info.colorspace=YIQColorspace;
  1084.                   if (Latin1Compare("yuv",option) == 0)
  1085.                     resource_info.colorspace=YUVColorspace;
  1086.                   if (resource_info.colorspace == UndefinedColorspace)
  1087.                     Error("Invalid colorspace type on -colorspace",option);
  1088.                 }
  1089.               break;
  1090.             }
  1091.           if (strncmp("comment",option+1,4) == 0)
  1092.             {
  1093.               comment=(char *) NULL;
  1094.               if (*option == '-')
  1095.                 {
  1096.                   i++;
  1097.                   if (i == argc)
  1098.                     Error("Missing comment on -comment",(char *) NULL);
  1099.                   comment=argv[i];
  1100.                 }
  1101.               break;
  1102.             }
  1103.           if (strncmp("compress",option+1,5) == 0)
  1104.             {
  1105.               compression=NoCompression;
  1106.               if (*option == '-')
  1107.                 {
  1108.                   i++;
  1109.                   if (i == argc)
  1110.                     Error("Missing type on -compress",(char *) NULL);
  1111.                   option=argv[i];
  1112.                   if (Latin1Compare("runlengthencoded",option) == 0)
  1113.                     compression=RunlengthEncodedCompression;
  1114.                   else
  1115.                     if (Latin1Compare("qencoded",option) == 0)
  1116.                       compression=QEncodedCompression;
  1117.                     else
  1118.                       Error("Invalid compression type on -compress",option);
  1119.                 }
  1120.               break;
  1121.             }
  1122.           if (strncmp("compose",option+1,5) == 0)
  1123.             {
  1124.               compose=ReplaceCompositeOp;
  1125.               if (*option == '-')
  1126.                 {
  1127.                   i++;
  1128.                   if (i == argc)
  1129.                     Error("Missing type on -compose",(char *) NULL);
  1130.                   option=argv[i];
  1131.                   compose=UndefinedCompositeOp;
  1132.                   if (Latin1Compare("over",option) == 0)
  1133.                     compose=OverCompositeOp;
  1134.                   if (Latin1Compare("in",option) == 0)
  1135.                     compose=InCompositeOp;
  1136.                   if (Latin1Compare("out",option) == 0)
  1137.                     compose=OutCompositeOp;
  1138.                   if (Latin1Compare("atop",option) == 0)
  1139.                     compose=AtopCompositeOp;
  1140.                   if (Latin1Compare("xor",option) == 0)
  1141.                     compose=XorCompositeOp;
  1142.                   if (Latin1Compare("plus",option) == 0)
  1143.                     compose=PlusCompositeOp;
  1144.                   if (Latin1Compare("minus",option) == 0)
  1145.                     compose=MinusCompositeOp;
  1146.                   if (Latin1Compare("add",option) == 0)
  1147.                     compose=AddCompositeOp;
  1148.                   if (Latin1Compare("subtract",option) == 0)
  1149.                     compose=SubtractCompositeOp;
  1150.                   if (Latin1Compare("difference",option) == 0)
  1151.                     compose=DifferenceCompositeOp;
  1152.                   if (Latin1Compare("replace",option) == 0)
  1153.                     compose=ReplaceCompositeOp;
  1154.                   if (compose == UndefinedCompositeOp)
  1155.                     Error("Invalid compose type on -compose",option);
  1156.                 }
  1157.               break;
  1158.             }
  1159.           Error("Unrecognized option",option);
  1160.           break;
  1161.         }
  1162.         case 'd':
  1163.         {
  1164.           if (strncmp("density",option+1,3) == 0)
  1165.             {
  1166.               density=(char *) NULL;
  1167.               if (*option == '-')
  1168.                 {
  1169.                   i++;
  1170.                   if ((i == argc) || !sscanf(argv[i],"%d",&x))
  1171.                     Error("Missing geometry on -density",(char *) NULL);
  1172.                   density=argv[i];
  1173.                 }
  1174.               break;
  1175.             }
  1176.           if (strncmp("display",option+1,3) == 0)
  1177.             {
  1178.               resource_info.server_name=(char *) NULL;
  1179.               if (*option == '-')
  1180.                 {
  1181.                   i++;
  1182.                   if (i == argc)
  1183.                     Error("Missing server name on -display",(char *) NULL);
  1184.                   resource_info.server_name=argv[i];
  1185.                 }
  1186.               break;
  1187.             }
  1188.           if (strncmp("dither",option+1,3) == 0)
  1189.             {
  1190.               resource_info.dither=(*option == '-');
  1191.               break;
  1192.             }
  1193.           Error("Unrecognized option",option);
  1194.           break;
  1195.         }
  1196.         case 'f':
  1197.         {
  1198.           if (strncmp("font",option+1,3) == 0)
  1199.             {
  1200.               resource_info.font=(char *) NULL;
  1201.               if (*option == '-')
  1202.                 {
  1203.                   i++;
  1204.                   if (i == argc)
  1205.                     Error("Missing font name on -font",(char *) NULL);
  1206.                   resource_info.font=argv[i];
  1207.                 }
  1208.               break;
  1209.             }
  1210.           if (strncmp("foreground",option+1,3) == 0)
  1211.             {
  1212.               resource_info.foreground_color=(char *) NULL;
  1213.               if (*option == '-')
  1214.                 {
  1215.                   i++;
  1216.                   if (i == argc)
  1217.                     Error("Missing foreground on -foreground",(char *) NULL);
  1218.                   resource_info.foreground_color=argv[i];
  1219.                 }
  1220.               break;
  1221.             }
  1222.           if (strncmp("frame",option+1,2) == 0)
  1223.             {
  1224.               frame=(*option == '-');
  1225.               break;
  1226.             }
  1227.           Error("Unrecognized option",option);
  1228.           break;
  1229.         }
  1230.         case 'g':
  1231.         {
  1232.           if (strncmp("gamma",option+1,2) == 0)
  1233.             {
  1234.               gamma=(char *) NULL;
  1235.               if (*option == '-')
  1236.                 {
  1237.                   i++;
  1238.                   if ((i == argc) || !sscanf(argv[i],"%f",(float *) &x))
  1239.                     Error("Missing value on -gamma",(char *) NULL);
  1240.                   gamma=argv[i];
  1241.                 }
  1242.               break;
  1243.             }
  1244.           if (strncmp("geometry",option+1,2) == 0)
  1245.             {
  1246.               resource_info.image_geometry=(char *) NULL;
  1247.               if (*option == '-')
  1248.                 {
  1249.                   i++;
  1250.                   if ((i == argc) || !sscanf(argv[i],"%d",&x))
  1251.                     Error("Missing geometry on -geometry",(char *) NULL);
  1252.                   resource_info.image_geometry=argv[i];
  1253.                 }
  1254.               break;
  1255.             }
  1256.           if (strncmp("gravity",option+1,2) == 0)
  1257.             {
  1258.               resource_info.gravity=CenterGravity;
  1259.               if (*option == '-')
  1260.                 {
  1261.                   i++;
  1262.                   if (i == argc)
  1263.                     Error("Missing type on -gravity",(char *) NULL);
  1264.                   option=argv[i];
  1265.                   resource_info.gravity=(-1);
  1266.                   if (Latin1Compare("Forget",option) == 0)
  1267.                     resource_info.gravity=ForgetGravity;
  1268.                   if (Latin1Compare("NorthWest",option) == 0)
  1269.                     resource_info.gravity=NorthWestGravity;
  1270.                   if (Latin1Compare("North",option) == 0)
  1271.                     resource_info.gravity=NorthGravity;
  1272.                   if (Latin1Compare("NorthEast",option) == 0)
  1273.                     resource_info.gravity=NorthEastGravity;
  1274.                   if (Latin1Compare("West",option) == 0)
  1275.                     resource_info.gravity=WestGravity;
  1276.                   if (Latin1Compare("Center",option) == 0)
  1277.                     resource_info.gravity=CenterGravity;
  1278.                   if (Latin1Compare("East",option) == 0)
  1279.                     resource_info.gravity=EastGravity;
  1280.                   if (Latin1Compare("SouthWest",option) == 0)
  1281.                     resource_info.gravity=SouthWestGravity;
  1282.                   if (Latin1Compare("South",option) == 0)
  1283.                     resource_info.gravity=SouthGravity;
  1284.                   if (Latin1Compare("SouthEast",option) == 0)
  1285.                     resource_info.gravity=SouthEastGravity;
  1286.                   if (Latin1Compare("Static",option) == 0)
  1287.                     resource_info.gravity=StaticGravity;
  1288.                   if (resource_info.gravity == (-1))
  1289.                     Error("Invalid gravity type on -gravity",option);
  1290.                 }
  1291.               break;
  1292.             }
  1293.           Error("Unrecognized option",option);
  1294.           break;
  1295.         }
  1296.         case 'h':
  1297.         {
  1298.           if (strncmp("help",option+1,2) == 0)
  1299.             {
  1300.               Usage();
  1301.               break;
  1302.             }
  1303.           Error("Unrecognized option",option);
  1304.           break;
  1305.         }
  1306.         case 'i':
  1307.         {
  1308.           if (strncmp("interlace",option+1,3) == 0)
  1309.             {
  1310.               interlace=NoneInterlace;
  1311.               if (*option == '-')
  1312.                 {
  1313.                   i++;
  1314.                   if (i == argc)
  1315.                     Error("Missing type on -interlace",(char *) NULL);
  1316.                   option=argv[i];
  1317.                   interlace=UndefinedInterlace;
  1318.                   if (Latin1Compare("none",option) == 0)
  1319.                     interlace=NoneInterlace;
  1320.                   if (Latin1Compare("line",option) == 0)
  1321.                     interlace=LineInterlace;
  1322.                   if (Latin1Compare("plane",option) == 0)
  1323.                     interlace=PlaneInterlace;
  1324.                   if (interlace == UndefinedInterlace)
  1325.                     Error("Invalid interlace type on -interlace",option);
  1326.                 }
  1327.               break;
  1328.             }
  1329.           Error("Unrecognized option",option);
  1330.           break;
  1331.         }
  1332.         case 'l':
  1333.         {
  1334.           if (strncmp("label",option+1,2) == 0)
  1335.             {
  1336.               label=(char *) NULL;
  1337.               if (*option == '-')
  1338.                 {
  1339.                   i++;
  1340.                   if (i == argc)
  1341.                     Error("Missing label name on -label",(char *) NULL);
  1342.                   label=argv[i];
  1343.                 }
  1344.               break;
  1345.             }
  1346.           Error("Unrecognized option",option);
  1347.           break;
  1348.         }
  1349.         case 'm':
  1350.         {
  1351.           if (strncmp("matte",option+1,2) == 0)
  1352.             {
  1353.               resource_info.matte_color=(char *) NULL;
  1354.               if (*option == '-')
  1355.                 {
  1356.                   i++;
  1357.                   if (i == argc)
  1358.                     Error("Missing color on -matte",(char *) NULL);
  1359.                   resource_info.matte_color=argv[i];
  1360.                 }
  1361.               break;
  1362.             }
  1363.           if (strncmp("monochrome",option+1,2) == 0)
  1364.             {
  1365.               resource_info.monochrome=(*option == '-');
  1366.               if (resource_info.monochrome)
  1367.                 {
  1368.                   resource_info.number_colors=2;
  1369.                   resource_info.tree_depth=8;
  1370.                   resource_info.colorspace=GRAYColorspace;
  1371.                 }
  1372.               break;
  1373.             }
  1374.           Error("Unrecognized option",option);
  1375.           break;
  1376.         }
  1377.         case 'p':
  1378.         {
  1379.           if (strncmp("page",option+1,2) == 0)
  1380.             {
  1381.               page_geometry=(char *) NULL;
  1382.               if (*option == '-')
  1383.                 {
  1384.                   i++;
  1385.                   if ((i == argc) || !sscanf(argv[i],"%d",&x))
  1386.                     Error("Missing page geometry on -page",(char *) NULL);
  1387.                   page_geometry=argv[i];
  1388.                 }
  1389.               break;
  1390.             }
  1391.           Error("Unrecognized option",option);
  1392.           break;
  1393.         }
  1394.         case 'q':
  1395.         {
  1396.           i++;
  1397.           if ((i == argc) || !sscanf(argv[i],"%d",&x))
  1398.             Error("Missing quality on -quality",(char *) NULL);
  1399.           quality=atoi(argv[i]);
  1400.           break;
  1401.         }
  1402.         case 'r':
  1403.         {
  1404.           degrees=0;
  1405.           if (*option == '-')
  1406.             {
  1407.               i++;
  1408.               if ((i == argc) || !sscanf(argv[i],"%f",(float *) &x))
  1409.                 Error("Missing degrees on -rotate",(char *) NULL);
  1410.               degrees=atoi(argv[i]);
  1411.             }
  1412.           break;
  1413.         }
  1414.         case 's':
  1415.         {
  1416.           if (strncmp("scene",option+1,3) == 0)
  1417.             {
  1418.               first_scene=0;
  1419.               last_scene=0;
  1420.               if (*option == '-')
  1421.                 {
  1422.                   i++;
  1423.                   if ((i == argc) || !sscanf(argv[i],"%d",&x))
  1424.                     Error("Missing scene number on -scene",(char *) NULL);
  1425.                   first_scene=atoi(argv[i]);
  1426.                   last_scene=first_scene;
  1427.                   (void) sscanf(argv[i],"%u-%u",&first_scene,&last_scene);
  1428.                 }
  1429.               break;
  1430.             }
  1431.           Error("Unrecognized option",option);
  1432.           break;
  1433.         }
  1434.         case 't':
  1435.         {
  1436.           if (strncmp("tiles_per_row",option+1,3) == 0)
  1437.             {
  1438.               tiles_per_row=0;
  1439.               if (*option == '-')
  1440.                 {
  1441.                   i++;
  1442.                   if ((i == argc) || !sscanf(argv[i],"%d",&x))
  1443.                     Error("Missing value on -tiles_per_row",(char *) NULL);
  1444.                   tiles_per_row=atoi(argv[i]);
  1445.                 }
  1446.               break;
  1447.             }
  1448.           if (strncmp("title",option+1,3) == 0)
  1449.             {
  1450.               resource_info.title=(char *) NULL;
  1451.               if (*option == '-')
  1452.                 {
  1453.                   i++;
  1454.                   if (i == argc)
  1455.                     Error("Missing title on -title",(char *) NULL);
  1456.                   resource_info.title=argv[i];
  1457.                 }
  1458.               break;
  1459.             }
  1460.           if (strncmp("treedepth",option+1,2) == 0)
  1461.             {
  1462.               resource_info.tree_depth=0;
  1463.               if (*option == '-')
  1464.                 {
  1465.                   i++;
  1466.                   if ((i == argc) || !sscanf(argv[i],"%d",&x))
  1467.                     Error("Missing depth on -treedepth",(char *) NULL);
  1468.                   resource_info.tree_depth=atoi(argv[i]);
  1469.                 }
  1470.               break;
  1471.             }
  1472.           Error("Unrecognized option",option);
  1473.           break;
  1474.         }
  1475.         case 'v':
  1476.         {
  1477.           verbose=(*option == '-');
  1478.           break;
  1479.         }
  1480.         default:
  1481.         {
  1482.           Error("Unrecognized option",option);
  1483.           break;
  1484.         }
  1485.       }
  1486.     else
  1487.       for (scene=first_scene; scene <= last_scene ; scene++)
  1488.       {
  1489.         Image
  1490.           *image,
  1491.           info_image;
  1492.  
  1493.         /*
  1494.           Option is a file name: begin by reading image from specified file.
  1495.         */
  1496.         start_time=time((time_t *) NULL);
  1497.         GetImageInfo(argv[i],&image_info);
  1498.         if (first_scene != last_scene)
  1499.           {
  1500.             char
  1501.               filename[MaxTextLength];
  1502.  
  1503.             /*
  1504.               Form filename for multi-part images.
  1505.             */
  1506.             (void) sprintf(filename,image_info.filename,scene);
  1507.             if (strcmp(filename,image_info.filename) == 0)
  1508.               (void) sprintf(filename,"%s.%u",image_info.filename,scene);
  1509.             (void) strcpy(image_info.filename,filename);
  1510.           }
  1511.         image_info.server_name=resource_info.server_name;
  1512.         image_info.font=resource_info.font;
  1513.         image_info.geometry=resource_info.image_geometry;
  1514.         image_info.page=page_geometry;
  1515.         image_info.density=density;
  1516.         image_info.interlace=interlace;
  1517.         image_info.monochrome=resource_info.monochrome;
  1518.         image_info.quality=quality;
  1519.         image_info.verbose=verbose;
  1520.         image=ReadImage(&image_info);
  1521.         if (image == (Image *) NULL)
  1522.           if (*option == '-')
  1523.             break;
  1524.           else
  1525.             continue;
  1526.         do
  1527.         {
  1528.           if (image->scene == 0)
  1529.             image->scene=image_number;
  1530.           info_image=(*image);
  1531.           LabelImage(image,label);
  1532.           /*
  1533.             Tile size maintains the aspect ratio of the image.
  1534.           */
  1535.           if (resource_info.image_geometry == (char *) NULL)
  1536.             TransformImage(&image,clip_geometry,"256x256");
  1537.           else
  1538.             TransformImage(&image,clip_geometry,resource_info.image_geometry);
  1539.           if ((degrees % 360) != 0)
  1540.             {
  1541.               Image
  1542.                 *rotated_image;
  1543.  
  1544.               /*
  1545.                 Rotate image.
  1546.               */
  1547.               rotated_image=RotateImage(image,(double) degrees,False);
  1548.               if (rotated_image != (Image *) NULL)
  1549.                 {
  1550.                   DestroyImage(image);
  1551.                   image=rotated_image;
  1552.                 }
  1553.             }
  1554.           if (gamma != (char *) NULL)
  1555.             GammaImage(image,gamma);
  1556.           if (verbose)
  1557.             {
  1558.               /*
  1559.                 Display detailed info about the image.
  1560.               */
  1561.               (void) fprintf(stderr,"[%u] %s",
  1562.                 image->scene == 0 ? image_number : image->scene,
  1563.                 image->filename);
  1564.               (void) fprintf(stderr," %ux%u",info_image.columns,
  1565.                 info_image.rows);
  1566.               if ((info_image.columns != image->columns) ||
  1567.                   (info_image.rows != image->rows))
  1568.                 (void) fprintf(stderr,"=>%ux%u",image->columns,image->rows);
  1569.               if (image->class == DirectClass)
  1570.                 (void) fprintf(stderr," DirectClass");
  1571.               else
  1572.                 (void) fprintf(stderr," PseudoClass %uc",image->colors);
  1573.               (void) fprintf(stderr," %s\n",image->magick);
  1574.             }
  1575.           /*
  1576.             Pack image data to conserve memory (memory <=> speed).
  1577.           */
  1578.           image->alpha=False;
  1579.           (void) RunlengthEncodeImage(image);
  1580.           (void) free((char *) image->pixels);
  1581.           image->pixels=(RunlengthPacket *) NULL;
  1582.           if (image_number == maximum_images)
  1583.             {
  1584.               /*
  1585.                 Increase size of images array.
  1586.               */
  1587.               maximum_images<<=1;
  1588.               images=(Image **)
  1589.                 realloc((char *) images,maximum_images*sizeof(Image *));
  1590.               if (images == (Image **) NULL)
  1591.                 Error("Unable to montage images","Memory allocation failed");
  1592.             }
  1593.           images[image_number++]=image;
  1594.           image=image->next;
  1595.         } while (image != (Image *) NULL);
  1596.       }
  1597.     }
  1598.   if (image_number == 0)
  1599.     Error("Missing an image file name",(char *) NULL);
  1600.   /*
  1601.     Create composite image.
  1602.   */
  1603.   montage_image=MontageImage(display,&resource_info,images,image_number,
  1604.     tiles_per_row,frame,compose);
  1605.   if (resource_info.number_colors != 0)
  1606.     {
  1607.       QuantizeImage(montage_image,resource_info.number_colors,
  1608.         resource_info.tree_depth,resource_info.dither,resource_info.colorspace,
  1609.         True);
  1610.       SyncImage(montage_image);
  1611.     }
  1612.   if (compression != UndefinedCompression)
  1613.     montage_image->compression=compression;
  1614.   (void) strcpy(montage_image->filename,write_filename);
  1615.   if (comment != (char *) NULL)
  1616.     CommentImage(montage_image,comment);
  1617.   (void) WriteImage(&image_info,montage_image);
  1618.   if (verbose)
  1619.     {
  1620.       /*
  1621.         Display detailed info about the image.
  1622.       */
  1623.       if (montage_image->class == DirectClass)
  1624.         montage_image->colors=NumberColors(montage_image,False);
  1625.       (void) fprintf(stderr,"[%u] %s %s=>%ux%u",montage_image->scene,
  1626.         montage_image->filename,montage_image->montage,montage_image->columns,
  1627.         montage_image->rows);
  1628.       if (montage_image->class == DirectClass)
  1629.         (void) fprintf(stderr," DirectClass ");
  1630.       else
  1631.         (void) fprintf(stderr," PseudoClass ");
  1632.       (void) fprintf(stderr,"%uc %s %lds\n",montage_image->colors,
  1633.         montage_image->magick,time((time_t *) NULL)-start_time+1);
  1634.     }
  1635.   DestroyImage(montage_image);
  1636.   (void) free((char *) images);
  1637.   if (display != (Display *) NULL)
  1638.     XCloseDisplay(display);
  1639.   return(False);
  1640. }
  1641.